﻿using Basic.Api.Filters;
using Basic.Api.Models;
using OF.Component.BLL;
using OF.Component.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http;
using System.Web.Security;
using System.Xml;
using Newtonsoft.Json;
using OF.Utility;
using OF.Utility.Logging;

namespace Basic.Api.Controllers
{
    /// <summary>
    /// 用户统一身份证认证接口
    /// </summary>
    [APIExceptionFilter]
    public class WxApiController : ApiController
    {
        ///声明Token
        public readonly string Token = "tokencheguantong"; //与微信公众账号后台的Token设置保持一致，区分大小写。

        /// <summary>
        /// string signature, string timestamp, string nonce, string echostr
        /// </summary>
        /// <returns></returns>
        [HttpGet, HttpPost]
        public HttpResponseMessage GateWay()
        {
            //string EchoStr = Valid(signature, timestamp, nonce, echostr);

            //if (!string.IsNullOrEmpty(EchoStr))
            //{

            //    return ToHttpMsgForWeChat(EchoStr);
            //}
            //else
            //{
            //    return ToHttpMsgForWeChat("验证失败");
            //}

            string weixin = "";

            weixin = PostInput(); //获取xml数据
            Log4netLog.Debug("收到数据：" + weixin);
            if (!string.IsNullOrEmpty(weixin))
            {
                return ResponseMsg(weixin); //调用消息适配器
            }
            return ToHttpMsgForWeChat("");
        }
        [HttpGet]
        public void SendTplMsg(string openid)
        {
            if (string.IsNullOrEmpty(openid))
            {
                openid = "ogc675sa2vEVioJHOv664tQE32hE";
            }
            var wx = new WxTemplateMsgHelper();
            var data = new
            {
                first = new { value = "尊敬的车主，您的爱车正接受服务，信息如下：",color="#00FF00" },
                keyword1 = new { value = "No.100223388", color="#173177" },
                keyword2 = new { value = "更换机油", color = "#173177" },
                keyword3 = new { value = "维修中", color = "#173177" },
                keyword4 = new { value = "2014-12-08 13:06:23", color = "#173177" },
                remark = new { value = "请您在“个人中心-我的服务单”查看您的爱车服务详细信息。", color = "#173177" }
            };

            wx.SendTemplete("NgJ97wv40Eq7XF5Pfb12DFbDP6t-obiHU0EOsZeua6g", openid, data);
          
        }


        #region 微信开发辅助方法

        private string Valid(string signature, string timestamp, string nonce, string echostr)
        {
            if (CheckSignature(signature, timestamp, nonce))
            {
                if (!string.IsNullOrEmpty(echostr))
                {
                    return echostr;
                }
            }

            return "";
        }

        /// <summary>
        /// 验证微信签名
        /// </summary>
        /// * 将token、timestamp、nonce三个参数进行字典序排序
        /// * 将三个参数字符串拼接成一个字符串进行sha1加密
        /// * 开发者获得加密后的字符串可与signature对比，标识该请求来源于微信。
        /// <returns></returns>
        private bool CheckSignature(string signature, string timestamp, string nonce)
        {
            string[] ArrTmp = {Token, timestamp, nonce};
            Array.Sort(ArrTmp); //字典排序
            string tmpStr = string.Join("", ArrTmp);
            tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
            tmpStr = tmpStr.ToLower();
            if (tmpStr == signature)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        public static HttpResponseMessage ToHttpMsgForWeChat(string strMsg)
        {
            HttpResponseMessage result = new HttpResponseMessage
            {
                Content = new StringContent(strMsg, Encoding.GetEncoding("UTF-8"), "application/x-www-form-urlencoded")
            };
            return result;
        }

        #endregion

        #region 获取post请求数据

        /// <summary>
        /// 获取post请求数据
        /// </summary>
        /// <returns></returns>
        private string PostInput()
        {
            Stream s = System.Web.HttpContext.Current.Request.InputStream;
            byte[] b = new byte[s.Length];
            s.Read(b, 0, (int) s.Length);
            return Encoding.UTF8.GetString(b);
        }

        #endregion

        #region 消息类型适配器

        private HttpResponseMessage ResponseMsg(string weixin) // 服务器响应微信请求
        {
            var oReturn = ToHttpMsgForWeChat("");
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(weixin); //读取xml字符串
            XmlElement root = doc.DocumentElement;
            ExmlMsg xmlMsg = GetExmlMsg(root);
            //XmlNode MsgType = root.SelectSingleNode("MsgType");
            //string messageType = MsgType.InnerText;
            string messageType = xmlMsg.MsgType; //获取收到的消息类型。文本(text)，图片(image)，语音等。


            try
            {

                switch (messageType)
                {
                    //当消息为文本时
                    case "text":
                        //textCase(xmlMsg);
                        break;
                    case "event":
                        //if (!string.IsNullOrEmpty(xmlMsg.EventName) && xmlMsg.EventName.Trim() == "subscribe")
                        //{
                        //    //刚关注时的时间，用于欢迎词  
                        //    int nowtime = ConvertDateTimeInt(DateTime.Now);
                        //    string msg = "你要关注我，我有什么办法。随便发点什么试试吧~~~";
                        //    string resxml = "<xml><ToUserName><![CDATA[" + xmlMsg.FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + xmlMsg.ToUserName + "]]></FromUserName><CreateTime>" + nowtime + "</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + msg + "]]></Content><FuncFlag>0</FuncFlag></xml>";
                        //    //Response.Write(resxml);

                        //}
                        string szMsg = "";
                        if (xmlMsg.EventName == "subscribe") //用户未关注时，进行关注后的事件推送
                        {
                            szMsg =
                                ($"未关注用户关注了公众号，EventKey:{xmlMsg.EventKey}，Ticket:{xmlMsg.Ticket},时间：{UnixTimeToTime(xmlMsg.CreateTime)}，FromUserName:{xmlMsg.FromUserName},ToUserName:{xmlMsg.ToUserName}");
                        }
                        else if (xmlMsg.EventName == "SCAN")
                        {
                            szMsg =
                                ($"已关注用户关注了公众号，EventKey:{xmlMsg.EventKey}，Ticket:{xmlMsg.Ticket},时间：{UnixTimeToTime(xmlMsg.CreateTime)}，FromUserName:{xmlMsg.FromUserName},ToUserName:{xmlMsg.ToUserName}");
                        }
                        Log4netLog.Debug(szMsg);
                        int nowtime = ConvertDateTimeInt(DateTime.Now);
                        string resxml = "<xml><ToUserName><![CDATA[" + xmlMsg.FromUserName +
                                        "]]></ToUserName><FromUserName><![CDATA[" + xmlMsg.ToUserName +
                                        "]]></FromUserName><CreateTime>" + nowtime +
                                        "</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[" + szMsg +
                                        "]]></Content><FuncFlag>0</FuncFlag></xml>";
                        oReturn = ToHttpMsgForWeChat(resxml);
                        break;
                    case "image":
                        break;
                    case "voice":
                        break;
                    case "vedio":
                        break;
                    case "location":
                        break;
                    case "link":
                        break;
                    default:
                        break;
                }

            }
            catch (Exception)
            {

            }
            return oReturn;
        }

        #endregion

        #region 将datetime.now 转换为 int类型的秒

        /// <summary>
        /// datetime转换为unixtime
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        private int ConvertDateTimeInt(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int) (time - startTime).TotalSeconds;
        }

        private int converDateTimeInt(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int) (time - startTime).TotalSeconds;
        }

        /// <summary>
        /// unix时间转换为datetime
        /// </summary>
        /// <param name="timeStamp"></param>
        /// <returns></returns>
        private DateTime UnixTimeToTime(string timeStamp)
        {
            DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            long lTime = long.Parse(timeStamp + "0000000");
            TimeSpan toNow = new TimeSpan(lTime);
            return dtStart.Add(toNow);
        }

        #endregion

        #region 接收的消息实体类 以及 填充方法

        private class ExmlMsg
        {
            /// <summary>
            /// 本公众账号
            /// </summary>
            public string ToUserName { get; set; }

            /// <summary>
            /// 用户账号
            /// </summary>
            public string FromUserName { get; set; }

            /// <summary>
            /// 发送时间戳
            /// </summary>
            public string CreateTime { get; set; }

            /// <summary>
            /// 发送的文本内容
            /// </summary>
            public string Content { get; set; }

            /// <summary>
            /// 消息的类型
            /// </summary>
            public string MsgType { get; set; }

            /// <summary>
            /// 事件名称
            /// </summary>
            public string EventName { get; set; }

            /// <summary>
            /// 事件KEY值
            /// </summary>
            public string EventKey { get; set; }

            /// <summary>
            /// 二维码的ticket，可用来换取二维码图片
            /// </summary>
            public string Ticket { get; set; }

        }

        private ExmlMsg GetExmlMsg(XmlElement root)
        {
            ExmlMsg xmlMsg = new ExmlMsg()
            {
                FromUserName = root.SelectSingleNode("FromUserName").InnerText,
                ToUserName = root.SelectSingleNode("ToUserName").InnerText,
                CreateTime = root.SelectSingleNode("CreateTime").InnerText,
                MsgType = root.SelectSingleNode("MsgType").InnerText,
            };
            if (xmlMsg.MsgType.Trim().ToLower() == "text")
            {
                xmlMsg.Content = root.SelectSingleNode("Content").InnerText;
            }
            else if (xmlMsg.MsgType.Trim().ToLower() == "event")
            {
                xmlMsg.EventName = root.SelectSingleNode("Event").InnerText;
                if (root.SelectSingleNode("EventKey") != null)
                {
                    xmlMsg.EventKey = root.SelectSingleNode("EventKey").InnerText;
                }
                if (root.SelectSingleNode("Ticket") != null)
                {
                    xmlMsg.Ticket = root.SelectSingleNode("Ticket").InnerText;
                }
            }
            return xmlMsg;
        }

        #endregion




    }

    /// <summary>
    /// 微信模板消息帮助类
    /// </summary>
    public class WxTemplateMsgHelper
    {
        private const string appid = "wxa357155c9581907c";
        private const string secret = "fb98cc7281154225ba9d5aae26e28955";

        /// <summary>
        /// 
        /// </summary>
        public class AccessToken
        {
            public string access_token { get; set; }
            public int expires_in { get; set; }
            public DateTime CreateDate { get; set; }


        }

        public void SendTemplete(string templateId, string toUser, object data)
        {
            var token = GetAccessToken();
            var postUrl = string.Format("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}",
                token);
            //注：url和miniprogram都是非必填字段，若都不传则模板无跳转；若都传，会优先跳转至小程序。开发者可根据实际需要选择其中一种跳转方式即可。当用户的微信客户端版本不支持跳小程序时，将会跳转至url。
            var msgData = new
            {
                template_id = templateId,
                touser = toUser,
                data = data,
                url="http://m.banmachewu.com",//跳转到URL
                topcolor="#FF0000", //已被腾讯禁用
                //miniprogram=new {//跳转到小程序
                //    //所需跳转到的小程序appid（该小程序appid必须与发模板消息的公众号是绑定关联关系）
                //    appid = "wxd9658c4601a224e7",
                //    pagepath = "pages/index/index"
                //},          


            };
            var j = JsonConvert.SerializeObject(msgData);
            var res = GetDataByPost(postUrl, j);


        }

        private string GetAccessToken()
        {
            var token = new AccessToken();
            var accessToken = CacheUtility.GetCache("accessToken", new string[] {});
            if (accessToken == null)
            {
                //获取TOKEN
                token = GetToken();
                CacheUtility.AddCache(token, "accessToken", new string[] {},100);

            }
            else
            {
                token = accessToken as AccessToken;
                //判断时间
                if (DateTime.Now > token.CreateDate.AddSeconds(token.expires_in))
                {
                    //获取TOKEN
                    token = GetToken();
                    CacheUtility.AddCache(token, "accessToken", new string[] {}, 100);
                }
            }


            var t = CacheUtility.GetCache("accessToken", new string[] {}) as AccessToken;
            return t.access_token;
        }

        private AccessToken GetToken()
        {
            string apiurl =
                $"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={secret}";
            string res = GetDataByPost(apiurl);
            var v = JsonConvert.DeserializeObject<AccessToken>(res);
            v.CreateDate = DateTime.Now;
            return v;
        }

        private string GetDataByPost(string url, string postData = "")
        {
            string result = "";
            byte[] byteData = Encoding.GetEncoding("UTF-8").GetBytes(postData);
            try
            {


                HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
                request.ContentType = "application/x-www-form-urlencoded";
                request.Referer = url;
                request.Accept = "*/*";
                request.Timeout = 30*1000;
                request.UserAgent =
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)";
                request.Method = "POST";
                request.ContentLength = byteData.Length;
                Stream stream = request.GetRequestStream();
                stream.Write(byteData, 0, byteData.Length);
                stream.Flush();
                stream.Close();
                HttpWebResponse response = (HttpWebResponse) request.GetResponse();
                Stream backStream = response.GetResponseStream();
                StreamReader sr = new StreamReader(backStream, Encoding.GetEncoding("UTF-8"));
                result = sr.ReadToEnd();
                sr.Close();
                backStream.Close();
                response.Close();
                request.Abort();
            }
            catch (Exception ex)
            {
                result = ex.Message;
            }
            return result;
        }
    }
}
